perm filename CONCEP.7[CLS,LSP] blob
sn#832104 filedate 1987-01-09 generic text, type T, neo UTF8
\input macros
\tolerance=2500
\def\bookline{\CLOS\ Specification}
\def\chapline{Programmer Interface Concepts}
\beginChapter 1.{Common Lisp Object System Specification}%
{Programmer Interface Concepts}{Programmer Interface Concepts}
Contributors to this document include Daniel G. Bobrow, Linda G.
DeMichiel,\break Richard P. Gabriel, Kenneth Kahn, Sonya E. Keene,
Gregor Kiczales, Larry\break Masinter, David A. Moon, Mark Stefik, and
Daniel L. Weinreb.
Comments and suggestions on this document are encouraged.
Changes will be incorporated over the next several months.
This text will be made available to the X3J13 Committee for the
Common Lisp Standards effort.
\endTitlePage
\beginSection{Introduction}
This proposal should be considered a working document. Although this draft is
not yet finished, we are presenting it for comments from the Common Lisp
community.
This proposal presents a description of the standard Programmer
Interface for object-oriented programming in the \CLOS. The first
chapter of this document describes the concepts of the \CLOS, and the
second gives an alphabetic list of functions that comprise the \CLOS\
Programmer Interface.
A second document, ``The \CLOS\ Meta-Object Protocol,'' describes how the
\CLOS\ can be customized to support other existing object-oriented
paradigms and how to define new ones.
The fundamental objects of the \CLOS\ are class objects, instances,
generic function objects, and method objects.
A {\bit class\/} object determines the structure and behavior of a set
of other objects, called its {\bit instances}. It is an important
feature of the \OS\ that every Common Lisp object is an {\bit
instance\/} of a class. The class of an object determines the set of
operations that can be performed on the object.
A {\bit generic function} is a function whose behavior depends on the
classes of the arguments supplied to it. A generic function comprises a
set of {\bit methods\/} (discussed below); these methods define the
class-specific behavior and operations of the generic function. Thus,
generic functions are objects that may be specialized to provide
class-specific operations; a generic function chooses one or more of a set
of possible operations based on the classes of its arguments. A generic
function is a function that can be used in precisely the same ways that
ordinary functions can be used in Common Lisp; in particular, a generic
function can be used as an argument to {\bf FUNCALL} and {\bf APPLY}, and
can be stored in the symbol-function cell of a symbol.
The class-specific operations provided by generic functions are themselves
defined and implemented by {\bit methods}. A method---also called a {\bit
method object}---is a function that can be used in any of the ways that
ordinary functions can be used in Common Lisp. A method object contains a
method function and a set of {\bit parameter specializers\/} that specify
when the given method is applicable.
To summarize, a generic function is a function that contains or
encompasses a number of methods. Each required formal parameter of each
method has an associated parameter specifier, and the method is expected
to be invoked only on arguments that satisfy these parameter
specifications. The purpose of the generic function is to provide the
object that contains all methods that provide the pieces of code that
define the behavior of the generic function. The naming conventions for
generic functions are precisely the same as those for ordinary Common
Lisp functions.
When a generic function is invoked, the classes of the required arguments
determine which methods might be applicable, and the behavior of the
generic function will result from the order in which methods are executed
and how their values are combined to produce the value or values for the generic
function. The {\bit method combination\/} facility controls the selection
of methods, the order in which they are run, and the values that are
returned by the generic function. The \CLOS\ offers a default method
combination type that is appropriate for most user programs. The \CLOS\ also
provides a facility for declaring a new type of method combination for
programs that require one.
\vfill
\endSection%{Introduction}
\beginSection{Classes}
A {\bit class\/} is an object that determines the structure and behavior
of a set of other objects, called its {\bit instances}.
Like other objects, all classes are themselves instances of classes. The
class of the class of an object is termed the {\bit metaclass\/} of that
object. Although it is less precise, we will use the term {\bit
metaclass\/} to refer to a class that has instances that are themselves
classes when no misinterpretation is possible. The metaclass determines
the form of inheritance used by the classes that are its instances and the
representation of the instances of those classes. The \CLOS\ provides a
default metaclass that is appropriate for most programs. The meta-object
protocol allows for defining and using new metaclasses.
A class can include other classes in its definition, in order to inherit
structure and behavior from those classes. The newly defined class is
called a {\bit subclass\/} of each of the classes that it includes. Each
of the classes that it includes is called a {\bit superclass\/} of the
newly defined class.
In situations where it matters whether a class is an immediate or,
equivalently, direct superclass or subclass of another, we will use the
following terminology. We will say that a class, $C↓1$, is a {\bit direct
superclass\/} of a class, $C↓2$, if the definition of $C↓2$ includes $C↓1$
as a superclass; we will say that $C↓2$ is a {\bit direct subclass\/} of
$C↓1$. We will say that a class, $C↓1$, is a {\bit superclass\/} of a
class, $C↑n$, if there exists series of classes, $C↓2,\ldots\,C↓{n-1}$
such that $C↓{i+1}$ is a direct superclass of $C↓i$, for $1≤i<n$;
in this case, we will say that $C↓n$ is a {\bit subclass\/} of
$C↓1$.
As an additional constraint, if $C↓1$ is a superclass of $C↓2$, then
$C↓1≠C↓2$. That is, a class is not considered a superclass of itself.
On occasion we will need to refer to the set of classes defined as
some given class along with all of its superclasses. We will call this
set ``the classes at or above C,'' where C is the given class.
When a class is defined including a set of direct superclasses, the order
in which those direct superclasses is mentioned in the defining form for
that newly defined class helps determine a total order on the classes at
or above that newly defined class. This order of the direct superclasses
is called the {\bit local precedence order\/} and will be discussed below.
%We don't need this. -Sonya
%\beginTermNote
%
%Symbolics, in their Flavors documentation, uses the term {\bit
%components\/} to refer to what we call the set of a classes at or above
%a given class; also, Symbolics uses the term {\bit superclass\/} to
%refer to what we call direct superclasses. In place of subclasses and
%direct subclasses, the Flavors document uses the terms {\bit
%dependents\/} and {\bit subclasses}, respectively.
%
%\endTermNote
Classes are organized into a {\bit lattice}, which gives them a partial
order called the lattice order. The top of the lattice is the class named
{\bf T} and the bottom is the class named {\bf NIL}. The lattice order
along with the local precedence order mentioned above usually combine to
produce a third partial order which can be embedded in a total order on
the classes at or above a given class; this third partial order will fail
to produce a total order when its two component partial orders are
inconsistent. The classes at or above a given class, placed in a list
according to the total order, is called the {\bit class precedence list}.
When, for a given class, a total order on the classes at or above a given
class cannot be determined, an error will be signalled during the normal
operations of the \CLOS, and we will normally consider as well-defined
only those class lattices with class precedence lists defined at every
class except the class named {\bf NIL}. The class precedence and its
computation will be discussed at length below.
There is a mapping from the Common Lisp type lattice
into the Common Lisp Object System class lattice. Many of the standard
Common Lisp types specified in {\it Common Lisp: The Language\/} by Guy
L. Steele Jr. have a corresponding class. Some Common Lisp types do
not have a corresponding class. The integration of the type and class
system is discussed later in this chapter.
%I removed this text for a couple reasons. -Sonya
%First, it's very confusing and doesn't belong so early in the
%introduction.
%Second, I hope we can improve the terminology.
%The \CLOS\ includes a set of standard objects. We use the term
%{\bit standard object\/} to refer to any object whose metaclass is
%{\bf class}. The class {\bf object} specifies the default behavior of the
%set of all objects whose metaclass is {\bf class}. In other words,
%all standard objects inherit (directly or indirectly) from the class
%{\bf object}.
%
%The \CLOS\ also defines a set of standard classes. A {\bit standard
%class\/} is any class that is an instance of the class {\bf class}.
%The class {\bf class} is itself of class {\bf class}. It is therefore
%both a standard class and a standard object. The class {\bf object}
%is also a standard class since it is also an instance of the class
%{\bf class}. As a standard object, the class {\bf class} is a
%subclass of the class {\bf object}.
\vfill\eject
\Vskip 1pc!
\boxfig
{\bf\tabskip 0pt plus 1fil
\halign to \hsize{\hfil\cr
array&hashtable&sequence\cr
atom*&integer&short-float\cr
bignum&keyword&simple-array\cr
bit&list&simple-bit-vector\cr
bit-vector&long-float&simple-string\cr
character&nil&simple-vector\cr
common*&null&single-float\cr
compiled-function&number&standard-char\cr
complex&package&stream\cr
cons&pathname&string\cr
double-float&random-state&string-char\cr
fixnum&ratio&symbol\cr
float&rational&t\cr
function&readtable&vector\cr
}}
\caption{Standard Common Lisp types. All these types except atom and common have\break
a corresponding class.}
\endfig
\beginsubSection{Defining Classes}
The macro {\bf DEFCLASS} is used to define new classes. The syntax for
{\bf DEFCLASS} is given in Figure~2-1.
There are four elements in a {\bf DEFCLASS} form. The first element is
the name of the new class.
The second element is the superclass list, which specifies the
direct superclasses of the class being defined. As mentioned above, the
\CLOS\ determines a class precedence list for the new class. The
class precedence list is used to order methods from most specific to least
specific and to allow a class to override options given by its
superclasses. The order of the classes in the superclass list in
the {\bf DEFCLASS} form determines a local precedence for classes; that
is, each class in the list must precede all classes to its right in the
final class precedence list. A detailed explanation of how the class
precedence list is computed is given in the section ``Determining the
Class Precedence List.''
The third element is the set of {\bit slot-specs\/}. Classes have named
slots, which define the structure of instances of the class, as do {\bf
DEFSTRUCT} slots. Each {\bit slot-spec\/} includes the name of the slot,
and optionally specifies one or more
{\bit slot-options\/}. A slot option pertains only to a single slot. If
a local description of a slot is provided, it completely overrides any
description of that slot inherited from a superclass.
The fourth element is the set of {\bit class-options\/}, which pertain
to the class as a whole.
The slot-options and class-options of the {\bf DEFCLASS} form allow for
the following:
\beginlist
\item{\bull} Providing an initial value form for one or more slots.
If an initial value form is supplied, when an
instance is created the initial value form is evaluated to produce a value
that is given to the slot.
\item{\bull} Requesting that methods for appropriately named generic functions
be automatically generated for reading or accessing one or more slots.
% what is this??? -rpg
% this is :initable-slots class option and :initable slot-option
% they are commented out now, pending initialization protocol. --Sonya
%\item{\bull} Specifying a keyword by which to initialize one or more slots.
%
\item{\bull} Controlling whether one copy of the slot is
shared by all instances or each instance has a copy of the
slot.
\item{\bull} Requesting that a constructor function be automatically
generated for making instances of this class.
\item{\bull} Indicating that the metaclass of instances of this class
should be other than the default metaclass.
\endlist
%[The next paragraph isn't true is it? {\bf defclass} can also be used to
%define classes that have other metaclasses, if they use the :metaclass
%option. -Sonya]
%Classes with metaclass {\bf class} (standard classes)
%are defined with the macro {\bf defclass}.
%The use and definition of classes with other metaclasses %are
%will be
%discussed in the chapter ``Meta-Object Protocol.''
%[The following isn't true, since the class precedence list includes
%the class
%itself, which is not in the transitive closure of all the classes in the
%includes list. -Sonya ]
%The transitive closure of all the classes in the {\it includes\/} list
%specifies all the classes that this class inherits from. An ordering of
%this list for purposes of precedence is called the {\bit class
%precedence list}.
%[I don't think we should discuss the class precedence list in detail here. -Sonya]
%The new class created by {\bf defclass} is a subclass of all the
%classes specified in the {\it includes\/} list of the {\bf defclass}
%form. A class that is defined in this way is the most specific
%element of a sublattice from which descriptions are inherited.
%[The class precedence list for a standard class is computed as follows:]
%
%1. A list is created, starting with the given class, of all the classes
%encountered in a depth-first traversal of
%the classes in the {\it includes\/} list of that class. The classes in
%the {\it includes\/} list are processed in left-to-right order (the order
%of local precedence).
%
%2. If more than one occurrence of a class appears in the list that
%results from step 1, only the last occurrence of that class is kept.
%
%3. It is verified that the list that results from step 2 preserves the
%local precedence indicated in the {\it includes\/} list of each class
%encountered. If any such local precedence is violated, an error is
%signalled.
\endsubSection
\beginsubSection{The Structure of Instances}
The definition of the class specifies the structure of instances of
the class. The slots define the structure of the instance.
There are two kinds of slots. An {\bf :instance} slot is a place where
data is stored in an instance. This is the most commonly used
kind of slot---each instance has an individual slot of the same
name. A {\bf :class} slot is a place where data is stored in a
class. There is only one slot, whose value is shared by all instances
of the class. The {\bf :allocation} slot option specifies whether the
slot is an {\bf :instance} slot or a {\bf :class} slot.
\endsubSection%{The Structure of Instances}
\beginsubSection{Creating Instances of Classes}
The function {\bf MAKE-INSTANCE} creates and returns a new instance of a
class. If the {\bf DEFCLASS} form indicates that some of the slots are
initializable, {\bf MAKE-INSTANCE} accepts arguments specifying the slots to
initialize and the initial values.
The initialization protocol is not yet specified.
\endsubSection%{Creating Instances of Classes}
%[I don't think we need this section. -Sonya]
%\beginsubSection{Superclasses}
%
%\endsubSection%{Superclasses}
\beginsubSection{Inheritance}
A class inherits slots and methods from its superclasses. Inheritance is
the key to program modularity within \CLOS. A typical object-oriented
program consists of several classes, each of which defines some aspect of
behavior. New classes are defined by including the appropriate classes as
superclasses, thus gathering desired aspects of behavior into one
class.
Slots and methods are inherited according to the class precedence list,
which is an ordered list of the classes above the given class.
The most specific element in the class precedence list is always
the class itself. This allows the class to override a slot description or
method inherited from any of its superclasses.
The inheritance of methods is described in detail in the section
``Method Selection and Combination.''
\endsubSection%{Inheritance}
%[I don't think we need this section. -Sonya]
%\beginsubSection{Class Precedence}
%
%brief introduction to notion of class precedence
%\endsubSection%{Class Precedence}
\beginsubSection{Accessing Slots}
Slots can be accessed in two ways: by use of the accessors defined in
the {\bf DEFCLASS} form and by use of the primitive function
{\bf SLOT-VALUE}.
The {\bf DEFCLASS} syntax allows for generating generic functions for
readers and accessors---these can be specified for individual slots or for
all slots. When a reader or accessor is requested for an individual slot,
the name of the generic function is directly specified; when readers and
accessors are requested for all slots, the names of the generic functions
are determined by combining a prefix and the individual slot names. If an
accessor is requested, a method is automatically generated for reading the
value of the slot, and a {\bf setf} method for it is also generated. If
a reader is requested, a method is automatically generated for reading the
value of the slot, but no {\bf setf} method for it is generated.
These methods are added to the appropriate generic functions.
The function {\bf SLOT-VALUE} can be used with any of the slot names
specified in the {\bf DEFCLASS} form to access a specific slot in an
object of the given class. If the object has no such slot, an error is
signalled. Note that {\bf SLOT-VALUE} can be used to read or write the
value of a slot whether or not the {\bf DEFCLASS} form used the
slot-options or class-options that specify accessor functions. When
{\bf SLOT-VALUE} is used, no methods for the accessors are executed.
The automatically-generated accessors specified in the {\bf DEFCLASS}
form are generic functions, which are implemented using {\bf
SLOT-VALUE}.
Sometimes it is convenient to access slots within the body of a method
or function. The macro {\bf WITH-SLOTS} can be used to set up a lexical
environment in which certain slots are lexically available. {\bf
WITH-SLOTS} enables one to specify whether the accessors or {\bf
SLOT-VALUE} should be used to access the slots.
\endsubSection
\beginsubSection{Integrating Types and Classes}
The \CLOS\ maps the Common Lisp type space into the space of classes.
Many but not all of the predefined Common Lisp type specifiers have a
class associated with them. For example, an array is of type {\bf
array}, and of class {\bf array}. Every class has a corresponding type.
A class that corresponds to a predefined Common Lisp type specifier is
called a {\bit standard-type-class}. Each standard-type-class has the
class {\bf standard-type-class} as a metaclass. Users can write methods that
dispatch on any primitive Common Lisp type that has a corresponding class.
However, it is not allowed to make an instance of a standard-type-class
with {\bf MAKE-INSTANCE}, or to include a standard-type-class as a
superclass of a class. Figure~1-2 displays part of the lattice of
standard-type-classes.
Creating a type by means of {\bf DEFSTRUCT} creates a class in this
lattice. Such a class is an instance of {\bf structure-class} and an
immediate subclass of the class that corresponds to the type given as
its {\bf :includes} argument. If no classes are included, the new class
is an immediate subclass of the class {\bf T}.
%Removed because the Figure 1-2 should show the ordering. -Sonya
%Will you fix it to reflect only those types that have classes?
%Converting a partial ordering to a total ordering for the sake of brevity,
%classes are ranked here in order from most specific to least specific:
%
%{\bf rational} {\bf float} {\bf number} {\bf symbol} {\bf list} {\bf
%vector} {\bf array} {\bf sequence}
%Removed because we aren't having classes for all these types. -Sonya
%The following precedence relations hold among classes:
%{\bf list} has precedence over {\bf symbol} (for {\bf nil});
%{\bf array} has precedence over {\bf sequence} (for vectors);
%{\bf vector} has precedence over {\bf simple-array} (for simple-vectors);
%{\bf bit-vector} has precedence over {\bf simple-array} (for simple-bit-vectors);
%and {\bf string} has precedence over {\bf simple-array} (for simple-strings).
%Removed because the idea of abstract classes is gone. -Sonya
%The classes {\bf number}, {\bf integer}, {\bf rational}, {\bf float},
%{\bf list}, and {\bf sequence} are {\bit abstract classes}, that is,
%they can never be directly instantiated. The function {\bf class-of}
%will never return one of these classes.
\endsubSection%{Integrating Types and Classes}
\eject
\beginsubSection{Lattice of classes that are instances of standard-type-class}
Note: This figure must be changed to remove the types that are not
going to have a class associated with them.
\fig{
\def\IgnoreLineBreaks{\catcode'15=9 \catcode'12=9}
\def\IgnoreWhiteSpace{\catcode'11=9 \catcode'40=9 \IgnoreLineBreaks}
\def\DontIgnoreWhiteSpace{\catcode'12=\active\catcode'15=5\catcode'11=10\catcode'40=10}
\font \pipefont= circlew10
\font \foofont = cmr10 at 1sp
\IgnoreWhiteSpace
\let \adv=\advance
\def\he{height}
\def\wi{width}
\def\de{depth}
\newdimen \stroke
\stroke= \fontdimen8\pipefont % thickness of line in circles
\newdimen \radius \radius=6pt % radius of circles
\newdimen\irad \irad=\radius\advance\irad by -.5\stroke
\newdimen\orad \orad=\radius\advance\irad by .5\stroke
\newbox\BStrutbox
\setbox\BStrutbox\hbox{\vrule\wi0pt\he8.5pt\de8.5pt}
\def\BoxStrut{\unhcopy\BStrutbox}
% Arrows
\newdimen\ArrowShift
\ArrowShift=\fontdimen22\tensy
\advance\ArrowShift by -0.5\stroke
\def\StrikeOut #1
{ \setbox0\hbox{#1}
\hbox to 1\wd0
{ \vrule \he\stroke\de0pt\wi\wd0
\hskip-\wd0
\unhbox0
}
}
\def\LeftArrow
{ \hskip 0.5\stroke
\StrikeOut{\lower\ArrowShift\hbox to 10pt{\tensy\char'40\hss}}
}
\def\RightArrow
{ \StrikeOut{\lower\ArrowShift\hbox to 10pt{\hss\tensy\char'41}}
\hskip 0.5\stroke
}
\def\ArrowLine
{ \StrikeOut{\hskip 10pt\hskip 0.5\stroke}
}
\def\LeftToRight
{ \let\RightSideArrow=\ArrowLine
\let\LeftSideArrow=\RightArrow
}
\def\RightToLeft
{ \let\LeftSideArrow=\ArrowLine
\let\RightSideArrow=\LeftArrow
}
\def\NoArrows
{ \let\LeftSideArrow=\ArrowLine
\let\RightSideArrow=\ArrowLine
}
% boxes around tokens
\let\NonterminalFont=\tenrm
\newbox\TStrutbox
\setbox0\hbox{\NonterminalFont{Bg}}
\setbox\TStrutbox\hbox{\vrule\wi0pt\he\ht0\de\dp0}
\def\TextStrut{\unhcopy\TStrutbox}
\def\HorzLine{\hrule \he \stroke \de 0pt}
\def\HFil{\leaders\HorzLine\hfil}
\def\HFill{\leaders\HorzLine\hfill}
\def\Nonterminal#1
{\setbox1\vbox to 0pt{
\vss
\hbox{\TextStrut\NonterminalFont\space#1\space\hskip-\stroke}
\vss}
\hbox{
\BoxStrut
\LeftSideArrow
\lower\irad\vbox{
\TopSquare
\copy1
\BotSquare}
\RightSideArrow}
}
\def\TopSquare
{ \hbox{
\vrule\he\stroke\de\irad\wi\stroke
\vrule\he\stroke\de0pt\wi\wd1
\vrule\he\stroke\de\irad\wi\stroke}
}
\def\BotSquare
{ \hbox{
\vrule\he\orad\de0pt\wi\stroke
\vrule\he\stroke\de0pt\wi\wd1
\vrule\he\orad\de0pt\wi\stroke}
}
\def\\#1{\Nonterminal{#1}\HFil}
\def\last#1{{\def\RightSideArrow{}\Nonterminal{#1}}}
% piping
\def\foo{\rlap{\foofont\char'40}}
\def\foo{}
\def\FulVert{\vrule \wi\stroke\foo\hskip-\stroke}
\def\TopVert{\vrule\de-\irad \wi\stroke\foo\hskip-\stroke}
\def\BotVert{\vrule\he-\orad \wi\stroke\foo\hskip-\stroke}
\def\Center#1,#2.
{\hskip\radius\foo#1\lower.5\stroke\hbox{\pipefont#2}\hskip\radius}
\def\ru{\char'10\hskip -2\radius}
\def\rd{\char'11\hskip -2\radius}
\def\ld{\char'12\hskip -2\radius}
\def\lu{\char'13\hskip -2\radius}
\def\thru{\hskip-\radius\vrule\he\stroke\de0pt\wi2\radius\hskip\radius\hskip-2\radius}
\def\Center#1,#2.
{\foo\hskip\radius#1{\pipefont#2\unskip}\hskip-\radius}
\def\LT{\Center\BotVert,\lu.}
\def\LU{\Center\FulVert,\lu.}
\def\LL{\Center\FulVert,\ld.}
\def\LB{\Center\TopVert,\ld.}
\def\LMid{\Center\TopVert\BotVert,\rd\ru\thru.}
\def\LMU{\Center\TopVert,\rd\thru.}
\def\LML{\Center\BotVert,\ru\thru.}
\def\LFD{\Center\FulVert,\ru\thru.}
\def\LS{\Center\TopVert\BotVert,\rd\ru.}
\def\RT{\Center\BotVert,\ru.}
\def\RU{\Center\FulVert,\ru.}
\def\RL{\Center\FulVert,\rd.}
\def\RB{\Center\TopVert,\rd.}
\def\RMid{\Center\TopVert\BotVert,\ld\lu\thru.}
\def\RMU{\Center\TopVert,\ld\thru.}
\def\RML{\Center\BotVert,\lu\thru.}
\def\Cross{\Center\FulVert,\thru.}
\def\LR{\Center,\thru.}
\def\TB{\Center\FulVert,.}
% ShiftBox
\newbox\x
\newbox\y
\newbox\tempy
\newbox\z
\newbox\tempz
\def\ShiftBox#1{
\savemod
\saverulebox
\setbox\x
\vbox{ \everycr{\noalign{{\modifyrulebox\global\setbox\z\hbox{}}}}
\halign{&\setbox\x\hbox{##}
\global \setbox\z\hbox{\unhbox\z\vrule\he\ht\x\de\dp\x\wi0pt}
\unhbox\x
\cr
#1}}%
\lower\ht\y\box\x\HFil
\restoremod
\restorerulebox
}
\def\saverulebox{
\setbox\tempy\box\y
\global \setbox\y\vbox{}
\setbox\tempz\box\z
\global \setbox\z\hbox{}
}
\def\restorerulebox{
\global \setbox\y\box\tempy
\global \setbox\z\box\tempz
}
\def\topmod{}
\def\thisrow{\global\let\modifyrulebox\firstmod}
\def\firstmod{
\global\setbox\y\vbox{\hrule\he0pt\wi0pt\de\dp\z}
\global\let\modifyrulebox\latermod
}
\def\latermod{
\global\setbox\y\vbox{\unvbox\y\hrule\he\ht\z\de\dp\z\wi0pt}
}
\def\savemod{
\let\tempmod\modifyrulebox
\global \let\modifyrulebox\topmod
}
\def\restoremod{
\global\let\modifyrulebox\tempmod
}
\DontIgnoreWhiteSpace
{\baselineskip0pt
\lineskip0pt
\LeftToRight
\IgnoreWhiteSpace
\def\ms{\os\os\os\os}
\def\os{\omit\span}
\hbox{
\\{NIL}
\ShiftBox{
\ms\LT\\{bit}&\RT\cr
\ms\ShiftBox{
\ShiftBox{
\ShiftBox{
\LU\\{fixnum}&\RT\cr
\LU\\{bignum}&\RMU\thisrow\cr
}\\{integer}&\RML\thisrow\cr
\LU\\{ratio}&\RB\cr
}\\{rational}&\RT\cr
\ShiftBox{
\LU\\{short-float}&\RT\cr
\LU\\{single-float}&\RMid\thisrow\cr
\LU\\{double-float}&\RL\cr
\LU\\{long-float}&\RB\cr
}\\{float}&\RMid\thisrow\cr
\LU\\{complex}&\RB\cr
}\\{number}&\RU\cr
\ms\LU\\{standard-char}\\{string-char}\\{character}&\RU\cr
\LU\\{keyword}&\os\os\os\RML\\{symbol}&\RU\cr
\LU\\{null}&\os\os\os\LS&\TB\cr
\LMid\\{cons}&\os\os\RMU\\{list}&\RML\\{sequence}&\RMid\thisrow\cr
\os\LL\\{simple-vector}&\LML\HFil&\RML\\{vector}&\LS&\TB\cr
\os\LL\\{simple-bit-vector}&\LFD\\{bit-vector}&\RL&\TB&\TB\cr
\os\LL\\{simple-string}&\LFD\\{string}&\RB&\TB&\TB\cr
\os\TB&\os\LB\HFil\\{simple-array}&\RMU\\{array}&\RL\cr
\ms\LL\\{stream}&\RL\cr
\ms\LL\\{hashtable}&\RL\cr
\ms\LL\\{readtable}&\RL\cr
\ms\LL\\{package}&\RL\cr
\ms\LL\\{pathname}&\RL\cr
\ms\LL\\{function}&\RL\cr
\ms\LL\\{compiled-function}&\RL\cr
\ms\LB\\{random-state}&\RB\cr
}
\last{T}}}
\hbox{}
}\caption{This figure shows all required subclass relationships among the classes that\break
are instances of
standard-type-class, with the exception of classes defined by means of\break
DEFSTRUCT. Implementations may choose to impose additional ones.}
\endfig
\endsubSection%{Types and Classes}
\endSection%{Classes}
\beginSection{Generic Functions and Methods}
\beginsubSection{Introduction to Generic Functions}
Like ordinary Lisp functions, generic functions take arguments, perform an
operation, and perhaps return useful values. An ordinary function has a
single body of code that is always executed when the function is called.
A generic function might perform a different series of operations and
combine the results of the operations in different ways, depending on the
class of one or more of the arguments. An argument that selects which
method or methods to run is called a {\bit specialized argument\/}. A
generic function can have several methods associated with it, and the
class of each specialized argument to the generic function indicates which
method or methods to use. The generic function is said to discriminate on
the classes of its arguments.
Ordinary functions and generic functions are called with identical
syntax:
(function-name arguments$\ldots$)
Generic functions are not only syntactically compatible with ordinary
functions; they are semantically compatible as well:
\beginlist
\item{\bull} They are true functions that can be passed as arguments and
used as the first argument to {\bf FUNCALL} and {\bf APPLY}.
\item{\bull} Generic functions are named precisely as are ordinary
functions. When a generic function is associated with a symbol, that name
is in a certain package and can be exported if it is part of an external
interface. This allows programmers to keep unrelated programs separate.
\endlist
Ordinary functions have a definition that is in one place; generic
functions have a distributed definition. The definition of a generic
function can be found in a set of {\bf DEFMETHOD} forms, possibly along
with a {\bf DEFGENERIC-OPTIONS} form that provides information about the
contract of the generic function. Evaluating these forms produces a
generic-function object. Typically a generic-function object is stored as
the function definition of the symbol that is the name of the generic
function.
When a new {\bf DEFGENERIC-OPTIONS} form is evaluated and the generic function
of this name already exists (that is, the function definition of the
first subform of {\bf DEFGENERIC-OPTIONS} is a generic-function object), the
existing generic-function object is modified. Evaluating a {\bf
DEFGENERIC-OPTIONS} does not modify any of the methods associated with the
generic function. When a {\bf DEFGENERIC-OPTIONS} form is evaluated and the
generic function of this name does not exist, it is created with no
methods.
\endsubSection%{Introduction to Generic Functions}
\beginsubSection{Introduction to Methods}
A {\bf DEFMETHOD} form contains the code that is to be run when the
specialized arguments to the generic function cause this method to be
selected. {\bf DEFMETHOD} creates a method-object. If a {\bf
DEFMETHOD} form is evaluated and the method-object already exists, the
new definition replaces the old.
Each method has a ``specialized'' lambda list, which indicates which of
its arguments are to be used for method selection. Only required
parameters can be specialized. [It is still under discussion whether
optional parameters can be specialized.] A specialized parameter
specifier is a list of ({\it variable-name parameter-specializer\/}),
where {\it parameter-specializer\/} is one of:
\beginlist
\item{\bull} The name of any class.
\item{\bull} ({\bf quote} {\it object\/})
\item{\bull} A symbol naming a standard-type-class corresponding to one of
these CL types:
\Vskip 1pc!
\boxfig
{\bf\tabskip 0pt plus 1fil
\halign to \hsize{\hfil\cr
array&integer&rational\cr
bit-vector*&list&readtable\cr
character&long-float&sequence\cr
compiled-function&null&short-float\cr
complex&number&single-float\cr
cons&package&string\cr
double-float&pathname&symbol\cr
float&random-state&t\cr
hashtable&ratio&vector\cr
}}
\endfig
\endlist
Note that a parameter-specializer is a symbol, and cannot be a list
such as ({\bf vector single-float}).
Methods can also have arguments not intended to be used for selection;
such parameter specifiers are in {\bf DEFUN} syntax.
A method with no specialized parameters is
a {\bit default method\/}; it is always part of the generic
function, but often shadowed by a more specific method. A default
method can also have a parameter specializer of {\bf T}; this is the
same as if that parameter had no specializer, sicne {\bf T} is the
class of all objects. An {\bit individual
method\/} is one whose specialized parameter is ({\bf QUOTE} {\it
object\/}); this method is selected if the corresponding argument to the
generic function is {\bf EQL} to the {\it object\/}.
The parameter specializer ({\bf QUOTE} {\it object\/}) is
more specific than any other specializer.
\beginTermNote
Sometimes methods with one specialized parameter are distinguished from
methods with more than one specialized parameter.
Usually, when this is done, a method
that has only one specialized parameter is called a {\bit classical\/}
method; a method with more than one specialized parameter is called a
{\bit multi-method\/}.
\endTermNote
Methods can have qualifiers, which give the method combination procedure a
way to distinguish between methods. If a method has no qualifier it is
called a primary method. Some examples of method qualifiers are: {\bf
:before}, {\bf :after}, and {\bf :around}. A {\bf :before} method
specifies code that runs before the primary method, and an {\bf :after}
method specifies code that runs after the primary method.
\endsubSection%{Introduction to Methods}
\beginsubSection{Congruent Lambda-lists for all Methods of a Generic Function}
The lambda-list in the {\bf DEFGENERIC-OPTIONS} specifies the ``shape''
of lambda-lists for its methods:
All methods for this generic function must be
congruent with this shape; this implies that the system can determine
whether a call is syntactically correct.
The shape of a lambda-list is defined as the number of required arguments,
the number of optional arguments, whether or not \&allow-other-keys appears,
the number and names of keyword arguments, and whether or not \&rest is used.
The rules are for congruence are:
[The following is a first approximation of these rules, which need
to be discussed further:]
\numitem{1.}Each method must have the same number of required arguments.
\numitem{2.}Each method must have the same number of \&optional arguments, but
methods can supply different defaults for \&optional arguments.
\numitem{3.}If \&allow-other-keys is used by one method, all methods must use
it.
\numitem{4.}If \&allow-other-keys is not used, each method must allow the same
number of \&key arguments, and these keyword arguments must have
the same keywords across methods.
\numitem{5.}If \&rest is used by one method, all methods must use it.
\numitem{6.}The use of \&aux need not be consistent across methods.
The method receives the same arguments that the generic function
received.
\endsubSection%{Congruent Lambda-lists for all Methods of a Generic Function}
\endSection%{Generic Functions and Methods}
\beginSection{Method Selection and Combination}
When a generic function is called, it must decide:
\beginlist
\item{\bull} Which method (or methods) to call
\item{\bull} The order in which to call the methods
\item{\bull} Which value (or values) to return
\item{\bull} If {\bf CALL-NEXT-METHOD} is used, it is important to know
which is the next method to call.
\endlist
These requirements are handled by the following four-step procedure:
\numitem{1.}Select the set of available methods.
Given a generic function and the arguments to it, the set of available
methods includes all methods for that generic function whose specialized
parameters match their corresponding arguments. A method's
specialized parameter matches its corresponding argument if:
\beginlist
\item{\bull} The class of the argument is the same as the class of the
specializer or is a subclass of it, or
\item{\bull} the specialized parameter is ({\bf quote} {\it object\/}) and
the argument is {\bf EQL} to the {\it object\/}.
\endlist
\numitem{2.}Sort the available methods into a precedence order.
To compare the precedence of two methods, examine their parameter
specializers
in the specified argument precedence order.
(Note that the left to right
precedence order is the default. It can be changed by the {\bf
:argument-precedence-order} option to {\bf DEFGENERIC-OPTIONS}.) Compare
the corresponding parameter specializers of the methods.
The first pair of parameter specializers that are not equal determine
the precedence. Method X is more specific than method Y if method X's
parameter specializer appears earlier than method Y's parameter specializer
in the class precedence list of the class of the argument. (Due to the
way the set of available methods is chosen, it is guaranteed that
the parameter specializers are present in the class precedence list of
the class of the argument.) Note that the ordering is simply alphabetical
with respect to the argument precedence order and the class precedence list.
Any unspecialized parameters have an implied parameter specializer of {\bf T}.
Because the class {\bf T} is the top of the class lattice,
{\bf T} is implied at the end of each class precedence list, so it
is less specific than any other class. ({\bf quote} {\it object\/}) is
more specific than any class. (If both parameter specializers are
quoted objects, they must be equal or both methods would not be
available for this argument.)
The resulting list of available methods is sorted with the most specific
method first and the least specific method at the end.
\numitem{3.}Apply method combination to the sorted list of methods.
The type of method combination specified for the generic function
receives the sorted list of available methods and returns a Lisp form.
This form contains calls to some or all of the methods, and defines the
value or values to be returned by the generic function. The method
combination might make some of the methods reachable via {\bf
CALL-NEXT-METHOD}, rather than calling them directly.
The meaning of the qualifiers of a method is defined entirely by this
step of the procedure. Method qualifiers give the method combination
procedure a way to distinguish between methods.
See ``Standard Method Combination'' for a description of how the default
method combination chooses methods to call, makes some methods available
by {\bf CALL-NEXT-METHOD}, and defines the values to be returned by the
generic function.
The {\bf DEFINE-METHOD-COMBINATION} facility enables the programmer to
customize this step of the procedure without needing to consider what
happens in the other steps. (The other steps of the procedure can be
customized using meta-objects.)
\numitem{4.}Evaluate the resulting Lisp form.
The semantics of generic function invocation requires that the effect must be
the same as if the form produced by this four-step procedure were simply
evaluated, and in some implementations this is precisely what happens.
Note that the four-step procedure takes a set of classes or {\bf quote}d
objects and a set of methods as its arguments, and after step~3 produces a
Lisp form that is evaluated in step~4.
Often, though, this four-step procedure is too inefficient and some
implementations do not follow it every time a generic function is called.
Instead they employ a variety of optimizations on the four-step procedure,
such as precomputation into tables, compilation, and/or caching to speed
things up. Some illustrative examples (not exhaustive) are:
\beginlist
\item{\bull} Use a hash table keyed by the class of the arguments to
store the resulting form.
\item{\bull} Compile the Lisp form and save the resulting compiled-function
in a table.
\item{\bull} Recognize the Lisp form as an instance of a pattern of
control structure and substitute a closure of a function that implements
that structure.
\endlist
Having the result of step~3 be a form that invokes methods and combines
their results rather than interleaving the invocation and combination of
methods with the process of determining those methods admits more
optimizations to the speed of the code and also enables more powerful
programming tools to be written. For example, a tool that determines
which methods are called and presents them to the user might work by going
through the first three steps of the above procedure and then analyzing
the form to determine which methods it calls, instead of evaluating it.
\endSection%{Method Selection and Combination}
\beginSection{Standard Method Combination}
The default type of method combination is called {\bf daemon}. A method's
type is specified by the qualifier arguments to {\bf DEFMETHOD}. The
following method types are recognized by {\bf daemon} method combination:
\def\numhangsize{60pt}
\numitem{Primary methods:}These methods have no qualifiers in the
{\bf DEFMETHOD} form. They are the most common type of method. {\bf
CALL-NEXT-METHOD} may be used in a primary method.
\numitem{{\bf :before} methods:}These methods have the keyword {\bf
:before} as their only {\bf DEFMETHOD} method-qualifier argument. They
are used to specify code that is to run before the primary method.
\numitem{{\bf :after} methods:}These have the keyword {\bf :after} as
their only {\bf DEFMETHOD} method-qualifier argument. They are used to
specify code that is to run after the primary method.
\numitem{{\bf :around} methods:}These methods have the keyword {\bf :around} as
their only {\bf DEFMETHOD} method-qualifier argument. Inside the body
of an {\bf :around} method, the function {\bf CALL-NEXT-METHOD} can be
used to immediately call the ``next method'' (see below). When the next
method returns, the {\bf :around} method can execute more code, perhaps
based on the returned value or values.
\def\numhangsize{25pt}
The semantics of {\bf daemon} method combination are:
\beginlist
\item{\bull} If there are any {\bf :around} methods, the most specific
{\bf :around} method is executed, and supplies the value or values of the
generic function.
\item{\bull} If an {\bf :around} method uses {\bf CALL-NEXT-METHOD}, the
next most specific {\bf :around} method is executed, if one is available.
\item{\bull} If there are no {\bf :around} methods at all, or if {\bf
CALL-NEXT-METHOD} is done by the least specific {\bf :around} method, the
other methods are executed in the following way:
\beginlist
\itemitem{--} All the {\bf :before} methods are executed, in
most-specific-first order.
\itemitem{--} The most specific primary method is executed, and supplies
the value or values returned by the generic function (or by {\bf
CALL-NEXT-METHOD} in the lease specific {\bf :around} method). If it does
{\bf CALL-NEXT-METHOD}, the second most specific primary method is
executed, and so on until there are no more primary methods. An error is
signalled if {\bf CALL-NEXT-METHOD} is used and there is no primary method
available to call.
\itemitem{--} All the {\bf :after} methods are executed in
most-specific-last order.
\endlist
\endlist
\beginRemarks
In {\bf daemon} combination, if there are any available methods at all,
then there must be an available primary method to produce the value or
values. In cases where there are available methods but no primary method
an error is signalled.
Suppose that all of the methods are primary methods. If {\bf
CALL-NEXT-METHOD} is not used, the most specific method only is invoked.
That is, more general methods are shadowed by more specific ones. If {\bf
CALL-NEXT-METHOD} is used, the effect is the same as {\bf RUN-SUPER} in
CommonLoops.
All {\bf :around} methods run before any primary
methods run. Thus a less specific {\bf :around} method runs before a more
specific primary method.
\endRemarks
This section has described the use of the default {\bf daemon} method
combination type and the default order, which is {\bf
:most-specific-first}. The {\bf :method-combination} option to {\bf
DEFGENERIC-OPTIONS} can be used to supply an argument of {\bf :most-specific-last}
to change the order of methods. {\bf :most-specific-last} reverses the
order of the primary methods. The order of the {\bf :before}, {\bf
:after}, and {\bf :around} methods is not changed, and it is still the
case that all of the {\bf :around} methods are executed before any primary
methods.
\endSection%{DAEMON Method Combination}
\beginSection{Determining the Class Precedence List}
The class precedence list is a total order on the set of superclasses of a
given class along with that class; the total order is expressed as a list.
A class precedence list is used in several ways. The method selection and
combination process uses the class precedence list to order methods from
most specific to least specific. When one class has several superclasses,
a more specific class can override some of the options declared in the {\bf DEFCLASS}
form of a less specific class. Some options are not inherited and therefore
need not be overridden.
\beginsubSection{Computing the Class Precedence List}
The class lattice imposes a partial order on the classes in the lattice,
called the lattice order; this partial order is that a class precedes its
direct superclasses. The {\bf DEFCLASS} form for each class provides a
second partial order, called the local precedence order; the local
precedence order is an ordered list of direct superclasses of a class. If
the local precedence order for a class, C, is $(C↓1\ldots C↓n)$, then
$C↓i$ precedes $C↓{i+1}$ for $1≤i<n$
Suppose we wish to compute the class precedence list at a class, C. Let
CL be the set of superclasses of C along with C itself: that is,
$cε\hbox{CL}$ if $c=\hbox{C}$ or $c$ is a superclass of~C. We define a new
partial order, P, on elements of CL to be the union of the lattice order on
the elements of the elements of CL and the local precedence order on the
elements of CL. The class precedence list of CL is a total order on the
elements of CL that is consistent with this new partial order.
To compute the class precedence list, we topologically sort the elements
of CL with respect to the partial order, P. A detailed
description of topological
sort can be found in Knuth, Volume~1, but a brief description of the
algorithm will be presented.
\beginsubsubsection{Topological Sorting}
Suppose S is a set of objects and R is a set of relations on objects
in S.
$$S=\{s↓1\ldots s↓n\}$$
\noindent and
$$R=\{(x,y)|x,yεS\}$$
Topological sorting proceeds by finding an element, $x$, in~S such that no other
element precedes that element according to the elements in~R. That element
of~S is placed first in the result. We remove $x$ from S, and we remove all
relations of the form $(x,y)$, $yεS$, from R. We repeat the process, adding
elements with no predecessors at the end of the result. We stop when no
element can be found that has no predecessor.
If S is not empty and the process has stopped, the order R is
inconsistent: if every element of a finite set is preceded by another,
then the relation contains a loop, and there are two elements, $x$ and $y$
such that $x<y$ and $y<x$. If at some point there are several elements
from S with no predecessors, then several total orderings are possible.
\endsubsubsection{Topological Sorting}
To resolve the ambiguity of several choices being possible at some point
in the topological sort for \CLOS, when there are several elements from S
with no predecessors---call the set of those elements NP---a a preorder
treewalk from the class C is preformed and the first element from NP that
is enumerated is selected.
A preorder treewalk is defined in terms of the order in which classes are
visited. We call the process of visiting classes in this order ``walking
from a class.'' Let $C$ be a class and let $\{C↓1\ldots C↓n\}$ be its
direct superclasses in the local precedence order. Nodes are visited
unless they have already been visited. To walk from $C$, first $C$ is
visited, then we walk from $C↓1$, then we walk from $C↓2$, and so on until
we finally walk from $C↓n$.
We require that an implementation of \CLOS\ signal an error if the
partial order is inconsistent, and we recommend that an implementation
provide a means for causing multiple total orders to signal an error.
\endsubSection%{Computing the Class Precedence List}
\beginsubSection{Example}
Here is an example of determining a class precedence list. The classes
are defined:
(defclass pie (apple cinnamon) ())
(defclass apple (fruit) ())
(defclass cinnamon (spice) ())
(defclass fruit (food) ())
(defclass spice (food) ())
(defclass food () ())
The set S~$=$ $\{$pie apple cinnamon fruit spice food$\}$. The set
R~$=$ $\{$(pie,apple) (pie,cinnamon) (apple,cinnamon) (apple,fruit)
(cinnamon,spice) (fruit,food) (spice,food)$\}$.
PIE is not preceded by anything, so it comes first;
the result so far is (PIE).
We remove
PIE from S and relations mentioning PIE from R and get
S~$=$ $\{$apple cinnamon fruit spice food$\}$ and
R~$=$ $\{$(apple,cinnamon) (apple,fruit) (cinnamon,spice) (fruit,food)
(spice,food)$\}$.
APPLE is not preceded by anything, so it is next; the result is
(PIE APPLE). Removing APPLE and the relevant relations we get
S~$=$ $\{$cinnamon fruit spice food$\}$ and
R~$=$ $\{$(cinnamon,spice) (fruit,food) (spice,food)$\}$.
CINNAMON and FRUIT are not preceded by anything, so we look at which
of these two comes first in the preorder treewalk. The preorder
treewalk visits classes in this order:
PIE, APPLE, FRUIT, FOOD, CINNAMON, SPICE.
Therefore we select FRUIT next, and the result so far is
(PIE APPLE FRUIT).
S~$=$ $\{$cinnamon spice food$\}$;
R~$=$ $\{$(cinnamon,spice) (spice,food)$\}$.
CINNAMON is next, giving the result so far as (PIE APPLE FRUIT CINNAMON).
S~$=$ $\{$spice food$\}$;
R~$=$ $\{$(spice,food)$\}$.
SPICE and FOOD are added in that order, and the class precedence list
is (PIE APPLE FRUIT CINNAMON SPICE FOOD). Note that several orderings
were possible because there was a point at which either FRUIT or CINNAMON
could have come next.
\endsubSection%{Example}
\beginsubSection{Conflicting Class Definitions}
It is possible to write a set of class definitions that cannot be
ordered. For example:
(defclass new-class (fruit apple) ())
(defclass apple (fruit) ())
FRUIT must precede APPLE because the local ordering of superclasses is
preserved. APPLE must precede FRUIT because a class always precedes its
own superclasses. When this situation occurs, an error is signalled
when the system tries to compute the class precedence list.
Note the following example, which appears at first glance to be a
conflicting set of definitions:
(defclass pie (apple cinnamon) ())
(defclass pastry (cinnamon apple) ())
The ordering for PIE is: (PIE APPLE CINNAMON)
The ordering for PASTRY is: (PASTRY CINNAMON APPLE)
There is no problem with the fact that APPLE precedes CINNAMON in the
ordering of the superclasses of PIE, but not in the ordering for PASTRY.
However, it is not possible to build a new class that has both PIE and
PASTRY as superclasses.
\endsubSection%{Conflicting Class Definitions}
\endSection%{Determining the Class Precedence List}
\beginSection{Declarative Method Combination}
We are currently working to integrate the programmatic ({\bf run-super})
and declarative ({\bf define-method-combination}) method combination
techniques. This is still under discussion.
\endSection%{Declarative Method Combination}
\beginSection{Meta Objects}
\beginsubSection{Metaclasses}
The {\bit metaclass\/} of an object is the class of its class. The
metaclass determines the form of inheritance used by its classes and the
representation of the instances of its classes. The metaclass mechanism
can be used to provide particular forms of optimization or to tailor the
\CLOS\ for particular uses (such as the implementation of other object
languages---like Flavors, Smalltalk-80, and Loops).
Any new metaclass must define the structure of its instances, how their
storage is allocated, how their slots are accessed, and how slots and
methods are inherited. The protocol for defining metaclasses will be
discussed in the chapter ``Meta-Object Protocol.''
\endsubSection
\beginsubSection{Standard Metaclasses}
The \CLOS\ defines a number of predefined metaclasses. These
include the following:
{\bf standard-type-class}, {\bf structure-class}, and {\bf class}.
The class {\bf standard-type-class} is a metaclass of all the classes
that correspond to the standard Common Lisp types specified in
{\it Common Lisp: The Language\/} by Guy L. Steele Jr.
%except {\bf atom} and {\bf common}.
These types are listed in Figure~1-1.
%next sentence removed because it sounds bogus and doesn't add anything. -Sonya
%
%This metaclass allows the special kind of class
%inheritance rules that are needed to handle the classes that
%correspond to the standard Common Lisp types.
It is not allowed to make an instance of a standard-type-class using
{\bf MAKE-INSTANCE}, or to use a standard-type-class
as a superclass of a user-defined class.
The class {\bf structure-class} is a subclass of {\bf standard-type-class}.
All classes defined by means of {\bf defstruct} are instances of
{\bf structure-class} or a subclass of {\bf structure-class}.
%The use of {\bf defstruct} implicitly defines a new class which is an
%instance of {\bf structure-class}.
%Instances of {\bf primitive-lisp-type-class} are classes that correspond
%to the basic Common Lisp types.
%While all classes that correspond to the types
%listed in Figure}1-1 must be instances of either {\bf structure-class}
%or {\bf primitive-lisp-type-class}, no implementation is {\it required\/} to
%have any class that is an instance of {\bf primitive-lisp-type-class}.
\endsubSection
\endSection
%\beginSection{Meta-Objects}
\CLOS\ provides several predefined meta-objects: {\bf generic-function}
(the default class of a generic function), {\bf method} (the default
class of a method), {\bf class} (the default class of a user-defined
class), and the standard method-combination type).
%Includes objects for classes, objects for methods, objects for generic functions.
%Use: efficiency in implementation; experimentation.
%Allows for variations in the representation of objects, the syntax of
%methods, the combination of methods.
%Can be used to provide tuning and optimization for a particular application.
%\endSection
\endChapter
\bye